
#include "stdio.h"
#include "stdlib.h"
#include "systick.h"
#include "../User/BSP/gd25q64/gd25q64.h"

uint8_t gd25q64Data[gd25q64DataLen] = {0};

/*!
    \brief      vgd25q64SPIInit
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vgd25q64SPIInit(void)
{
    rcu_periph_clock_enable(gd25q64RCU_SPIx);
    rcu_periph_clock_enable(gd25q64RCU_GPIOx);
    rcu_periph_clock_enable(RCU_AF);

    gpio_init(gd25q64GPIOx, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, gd25q64GPIO_PIN_x);
    gpio_init(gd25q64GPIOx, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, gd25q64SPI_CS_PIN_x);
    gpio_bit_write(gd25q64GPIOx, gd25q64SPI_CS_PIN_x, SET);

    spi_parameter_struct  spi_init_struct;
    spi_i2s_deinit(SPI0);

    spi_struct_para_init(&spi_init_struct);

    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.prescale             = SPI_PSC_32;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;

    spi_init(SPI0, &spi_init_struct);

    spi_enable(SPI0);
}


/*!
    \brief      spi_master_send_recv_byte
    \param[in]  sourcedata
    \param[out] none
    \retval     none
*/
uint8_t spi_master_send_recv_byte(uint8_t sourcedata)
{
    uint8_t ByteRecv;
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE))
        ;
    spi_i2s_data_transmit(SPI0, sourcedata);
    while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
        ;
    ByteRecv = spi_i2s_data_receive(SPI0);
    return ByteRecv;
}
/*!
    \brief      spi_master_recv_some_bytes
    \param[in]  *sourcedata
    \param[in]  length
    \param[out] none
    \retval     none
*/
void spi_master_recv_some_bytes( uint8_t *sourcedata, uint16_t length)
{
    uint8_t *temp_data = sourcedata;

    while (length--)
    {
        *temp_data = spi_master_send_recv_byte(0xFF);	//发送 0xff 为从设备提供时钟
        temp_data++;
    }
}
/*!
    \brief      vgd25q64WriteEnable
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vgd25q64WriteEnable(void)
{
    GD25Q64_CS_LOW();
    spi_master_send_recv_byte(GD25Q64_WriteEnable);
    GD25Q64_CS_HIGH();
}
/*!
    \brief      ucgd25q64ReadStatusRegister
    \param[in]  GD25Q64_ReadStatusRegisterx
    \param[out] none
    \retval     none
*/
uint8_t ucgd25q64ReadStatusRegister(uint8_t GD25Q64_ReadStatusRegisterx)
{
    GD25Q64_CS_LOW();
    spi_master_send_recv_byte(GD25Q64_ReadStatusRegisterx);
    uint8_t StatusRegisterx = spi_master_send_recv_byte(0xFF);
    GD25Q64_CS_HIGH();
    return StatusRegisterx;
}
/*!
    \brief      vgd25q64WriteStatusRegisterx
    \param[in]  sourcedata
    \param[in]  GD25Q64_ReadStatusRegisterx
    \param[out] none
    \retval     none
*/
void vgd25q64WriteStatusRegisterx(uint8_t sourcedata, uint8_t GD25Q64_ReadStatusRegisterx)
{
    vgd25q64WriteEnable();
    while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
        ;
    GD25Q64_CS_LOW();
    spi_master_send_recv_byte(GD25Q64_ReadStatusRegisterx);
    spi_master_send_recv_byte(sourcedata);
    GD25Q64_CS_HIGH();
}

/*!
    \brief      vgd25q64EraseSector
    \param[in]  eraseAddr
    \param[out] none
    \retval     none
*/
void vgd25q64EraseSector(uint32_t eraseAddr)
{
    vgd25q64WriteEnable();
    while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
        ;
    GD25Q64_CS_LOW();
    spi_master_send_recv_byte(GD25Q64_SectorErase);
    spi_master_send_recv_byte((uint8_t)(eraseAddr >> 16));
    spi_master_send_recv_byte((uint8_t)(eraseAddr >> 8));
    spi_master_send_recv_byte((uint8_t)(eraseAddr));
    GD25Q64_CS_HIGH();
    while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
        ;
}


/*!
    \brief      Flash_Erase_AppointSector
    \param[in]  start add
    \param[in]  end add
    \param[out] none
    \retval     none
*/
void vgd25q64EraseAppointSector(uint32_t addstart, uint32_t addend)
{
    uint32_t startsector =  addstart / GD25Q64_SectorSize * GD25Q64_SectorSize;
    uint32_t endsector   =  addend / GD25Q64_SectorSize * GD25Q64_SectorSize;
    uint32_t erasesectornum = (endsector / GD25Q64_SectorSize) - (startsector / GD25Q64_SectorSize);
    for(uint8_t i = 0; i <= erasesectornum; i++)
    {
        vgd25q64EraseSector(startsector + i * GD25Q64_SectorSize);
    }
}






/*!
    \brief      Flash_EraseChip
    \param[in]  none
    \param[out] none
    \retval     none
*/
void Flash_EraseChip(void)
{
    vgd25q64WriteEnable();
    while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
        ;
    GD25Q64_CS_LOW();
    spi_master_send_recv_byte(GD25Q64_ChipErase);
    GD25Q64_CS_HIGH();
    while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
        ;
}
/*!
    \brief      uigd25q64ReadIdentification
    \param[in]  none
    \param[out] Identification
    \retval     none
*/
unsigned int uigd25q64ReadIdentification(void)
{
    uint32_t Identification = 0;
    uint8_t recv_buff[3] = {0};

    GD25Q64_CS_LOW();

    spi_master_send_recv_byte(GD25Q64_ReadIdentification);	//9fh

    uint8_t recvLen = sizeof(recv_buff);

    for(uint8_t i = 0 ; i < recvLen; i++)
    {
        recv_buff[i] = spi_master_send_recv_byte(0xFF);	//发送 0xff 为从设备提供时钟
    }

    Identification = (recv_buff[0] << 16) | (recv_buff[1] << 8) | (recv_buff[2]);

    GD25Q64_CS_HIGH();

    return Identification;
}
/*!
    \brief      usgd25q64ReadID
    \param[in]  none
    \param[out] ID
    \retval     none
*/
unsigned short usgd25q64ReadID(void)
{
    uint16_t ID = 0;
    GD25Q64_CS_LOW();

    spi_master_send_recv_byte(GD25Q64_ManufacturerDeviceID);
    spi_master_send_recv_byte(0x00);
    spi_master_send_recv_byte(0x00);
    spi_master_send_recv_byte(0x00);

    ID |= spi_master_send_recv_byte(0xFF) << 8;
    ID |= spi_master_send_recv_byte(0xFF);

    GD25Q64_CS_HIGH();

    return ID;
}
uint8_t tempdata[1024] = {0};
/*!
    \brief      vgd25q64WriteData
    \param[in]  *sourcedata
    \param[in]  address
    \param[in]  length
    \param[out] none
    \retval     none
*/
void vgd25q64WriteData(uint8_t *sourcedata, uint32_t address, uint32_t length)
{
    uint32_t currentGroup = 0;
    uint32_t DataAdd = address;
    uint32_t currentLen = length, residuelength = length;
    do
    {
        //vgd25q64ReadData(gd25q64Data,PosGD25Q64_TaskInfo_num_I,GD25Q64_SectorSize);
        if(currentLen > (GD25Q64_PageSize))
        {
            currentLen = GD25Q64_PageSize;
        }
        vgd25q64WriteEnable();
        while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
            ;
        GD25Q64_CS_LOW();
        spi_master_send_recv_byte(GD25Q64_PageProgram);
        spi_master_send_recv_byte(DataAdd >> 16);
        spi_master_send_recv_byte(DataAdd >> 8);
        spi_master_send_recv_byte(DataAdd >> 0);
        for(uint32_t i = 0; i < currentLen; i++)
        {
            spi_master_send_recv_byte(sourcedata[i + (currentGroup * GD25Q64_PageSize)]);
        }

        GD25Q64_CS_HIGH();
        while(((ucgd25q64ReadStatusRegister(GD25Q64_ReadStatusRegister1)) & 0x01) == 0x01)
            ;
        residuelength -= (GD25Q64_PageSize);
        currentLen = residuelength;
        DataAdd += GD25Q64_PageSize;
    }
    while((++currentGroup) < (length / (GD25Q64_PageSize)));
}
/*!
    \brief      vgd25q64ReadData
    \param[in]  *sourcedata
    \param[in]  address
    \param[in]  length
    \param[out] none
    \retval     none
*/
void vgd25q64ReadData(uint8_t *sourcedata, uint32_t address, uint32_t length)
{
    uint8_t *temp_data = sourcedata;

    GD25Q64_CS_LOW();

    spi_master_send_recv_byte(GD25Q64_ReadData);
    spi_master_send_recv_byte((uint8_t)(address >> 16));
    spi_master_send_recv_byte((uint8_t)(address >> 8));
    spi_master_send_recv_byte((uint8_t)(address >> 0));

    while (length--)
    {
        *temp_data = spi_master_send_recv_byte(0xFF);	//发送 0xff 为从设备提供时钟
        temp_data++;
    }

    GD25Q64_CS_HIGH();
}

/*!
    \brief      vgd25q64FlushWrite  erase -> write
    \param[in]  *data
    \param[in]  add
    \param[in]  length
    \param[out] none
    \retval     none
*/
void vgd25q64FlushWrite(uint8_t	*sourcedata, uint32_t address, uint32_t length)
{

    uint32_t startSectorAddress = ((address / GD25Q64_SectorSize) * GD25Q64_SectorSize);
    uint32_t endSectorAddress = (((address + length) / GD25Q64_SectorSize) * GD25Q64_SectorSize);
    uint32_t startAddress = address % GD25Q64_SectorSize;
    if(startSectorAddress == endSectorAddress)
    {
        vgd25q64ReadData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);
        for(uint32_t i = 0; i < length; i++)
        {
            gd25q64Data[i + startAddress] = sourcedata[i];
        }
        vgd25q64EraseSector(address);
        vgd25q64WriteData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);
    }
    else
    {

        vgd25q64ReadData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);
        for(uint32_t i = 0; i < (GD25Q64_SectorSize - startAddress); i++)
        {
            gd25q64Data[i + startAddress] = sourcedata[i];
        }
        vgd25q64EraseSector(startSectorAddress);
        vgd25q64WriteData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);

        uint32_t enddatalen = length - (GD25Q64_SectorSize - startAddress);
        vgd25q64ReadData(gd25q64Data, endSectorAddress, GD25Q64_SectorSize);
        for(uint32_t i = 0; i < enddatalen; i++)
        {
            gd25q64Data[i] = sourcedata[(GD25Q64_SectorSize - startAddress) + i];
        }
        vgd25q64EraseSector(endSectorAddress);
        vgd25q64WriteData(gd25q64Data, endSectorAddress, GD25Q64_SectorSize);
    }
    vgd25q64ReadData(tempdata, address, 256);
    vrs485Send(tempdata, 256);
}

void vgd25q64FlushDel(uint32_t address, uint32_t length)
{

    uint32_t startSectorAddress = ((address / GD25Q64_SectorSize) * GD25Q64_SectorSize);
    uint32_t endSectorAddress = (((address + length) / GD25Q64_SectorSize) * GD25Q64_SectorSize);
    uint32_t SectorinterstartAddress = (address - startSectorAddress);
    if(startSectorAddress == endSectorAddress)
    {
        vgd25q64ReadData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);
        vgd25q64EraseSector(startSectorAddress);

        //write Previous
        vgd25q64WriteData(gd25q64Data, startSectorAddress, SectorinterstartAddress);

        //write subsequent
        vgd25q64WriteData(&gd25q64Data[SectorinterstartAddress + length], startSectorAddress + SectorinterstartAddress + length, GD25Q64_SectorSize - SectorinterstartAddress - length);

    }
    else
    {

        //startSectorAddress
        vgd25q64ReadData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize);
        vgd25q64EraseSector(startSectorAddress);
        vgd25q64WriteData(gd25q64Data, startSectorAddress, GD25Q64_SectorSize - SectorinterstartAddress);

        //endSectorAddress
        vgd25q64ReadData(gd25q64Data, endSectorAddress, GD25Q64_SectorSize);
        vgd25q64EraseSector(endSectorAddress);
        uint32_t endSectorWriteAdd = (SectorinterstartAddress + length) % GD25Q64_SectorSize;
        vgd25q64WriteData(&gd25q64Data[endSectorWriteAdd], endSectorAddress + endSectorWriteAdd, GD25Q64_SectorSize - endSectorWriteAdd);

        //middleSector
        for(uint32_t s = startSectorAddress + GD25Q64_SectorSize; s < endSectorAddress; s += GD25Q64_SectorSize)
        {
            vgd25q64EraseSector(s);
        }
    }
}





//void vgd25q64MoveSectorData(){
//
//}




